package com.byit.aspect;

import com.alibaba.fastjson.JSONObject;
import com.byit.domain.SysLog;
import com.byit.domain.SysUser;
import com.byit.log.Log;
import com.byit.msg.MessageResult;
import com.byit.service.ISysLogService;
import com.byit.utils.AddressUtil;
import com.byit.utils.ServletUtil;
import com.byit.utils.ShiroUtils;
import com.byit.utils.StringUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 操作日志记录处理
 *
 * @author wangx
 */
@Aspect
@Component
@EnableAsync
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    private ISysLogService sysLogService;

    // 配置织入点
    @Pointcut("@annotation(com.byit.log.Log)")
    public void logPointCut() {
    }

    /**
     * 前置通知 用于拦截操作
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "result")
    public void doBefore(JoinPoint joinPoint, Object result) {
        handleLog(joinPoint, null, result);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, (Object) null);
    }

    @Async
    protected void handleLog(final JoinPoint joinPoint, final Exception e, final Object result) {
        try {
            // 获得注解
            Log log = getAnnotationLog(joinPoint);
            if (log == null) {
                return;
            }
            insertLog(log, joinPoint, result, e);
        } catch (Exception exp) {
            // 记录本地异常日志
            logger.error("==前置通知异常==");
            logger.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    private void insertLog(Log log, JoinPoint joinPoint, Object result, Exception e) {

        SysLog sysLog = new SysLog();
        // 设置action动作
        sysLog.setOperType(log.operate());
        // 设置标题
        sysLog.setTitle(log.title());
        // 设置channel
        sysLog.setChannel(log.channel());
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        sysLog.setMethod(className + "." + methodName + "()");

        sysLog.setOperTime(new Date());

        Map<String, String[]> map = ServletUtil.getRequest().getParameterMap();
        String params = JSONObject.toJSONString(map);
        sysLog.setOperParam(StringUtil.substring(params, 0, 255));

        sysLog.setErrorMsg("操作成功!");

        if (null != result && result instanceof MessageResult) {
            MessageResult mr = (MessageResult) result;
            String code = (String) mr.getCode();
            if (null != code && !"000".equals(code)) {
                sysLog.setStatus("2");
                sysLog.setErrorMsg(mr.getCode());
            }
        }

        if (e != null) {
            sysLog.setStatus("1");
            sysLog.setErrorMsg(StringUtil.substring(e.getMessage(), 0, 2000));
        }

        // 获取当前的用户
        SysUser user = ShiroUtils.getUser();
        if (user != null) {
            sysLog.setOperName(user.getLoginName());
        }
        // 请求的地址
        String ip = ShiroUtils.getIp();
        sysLog.setOperIp(ip);
        // 操作地点
        sysLog.setOperLocation(AddressUtil.getRealAddressByIP(ip));
        sysLog.setOperUrl(ServletUtil.getRequest().getRequestURI());
        sysLogService.insert(sysLog);
    }

    /**
     * 是否存在注解，如果存在就获取
     */
    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }
}
